import Util;
import OSSUtil;
import FileForm;
import XML;

type @endpoint = string
type @regionId = string
type @protocol = string
type @userAgent = string
type @readTimeout = number
type @connectTimeout = number
type @httpProxy = string
type @httpsProxy = string
type @noProxy = string
type @maxIdleConns = number
type @hostModel = string
type @addtionalHeaders = [ string ]

model Config {
  credentialType?: string,
  securityToken?: string,
  accessKeyId: string,
  accessKeySecret: string,
  endpoint: string,
  protocol?: string,
  regionId: string,
  userAgent?: string,
  hostModel?: string,
  signatureVersion?: string,
  isEnableMD5?: boolean,
  isEnableCrc?: boolean,
  readTimeout?: number,
  connectTimeout?: number,
  localAddr?: string,
  httpProxy?: string,
  httpsProxy?: string,
  noProxy?: string,
  socks5Proxy?: string,
  socks5NetWork?: string,
  maxIdleConns?: number,
  addtionalHeaders?: [ string ],
}

init(config: Config){
  if (Util.isUnset(config)) {
    throw {
      name = "ParameterMissing",
      message = "'config' can not be unset"
    };
  }

  if (Util.empty(config.endpoint)) {
    throw {
      name = "ParameterMissing",
      message = "'config.endpoint' can not be empty"
    };
  }

  if (Util.empty(config.regionId)) {
    throw {
      name = "ParameterMissing",
      message = "'config.regionId' can not be empty"
    };
  }
  @endpoint = config.endpoint;
  @protocol = config.protocol;
  @regionId = config.regionId;
  @userAgent = config.userAgent;
  @readTimeout = config.readTimeout;
  @connectTimeout = config.connectTimeout;
  @httpProxy = config.httpProxy;
  @httpsProxy = config.httpsProxy;
  @noProxy = config.noProxy;
  @maxIdleConns = config.maxIdleConns;
  @addtionalHeaders = config.addtionalHeaders;
}

model PostObjectRequest = {
  bucketName: string(description='BucketName', name='BucketName', pattern='[a-zA-Z0-9-_]+'),
  header: {
    accessKeyId: string(description='OSSAccessKeyId', name='OSSAccessKeyId'),
    policy: string(description='policy', name='policy'),
    signature: string(description='Signature', name='Signature'),
    successActionStatus?: string(description='success_action_status', name='success_action_status'),
    file: FileForm.FileField,
    key: string(description='key', name='key'),
    userMeta?: map[string]string(description='UserMeta', name='UserMeta')
  }(description='header', name='header')
}

model PostObjectResponse = {
  postResponse: {
    bucket: string(description='Bucket', name='Bucket'),
    eTag: string(description='ETag', name='ETag'),
    location: string(description='Location', name='Location'),
  }(description='PostResponse', name='PostResponse'),
}

api postObject(request: PostObjectRequest, runtime: OSSUtil.RuntimeOptions): PostObjectResponse {
  var boundary = FileForm.getBoundary();
  __request.protocol = @protocol;
  __request.method = 'POST';
  __request.pathname = `/`;
  __request.headers = {
    host = OSSUtil.getHost(request.bucketName, @regionId, @endpoint, @hostModel),
    date = Util.getDateUTCString(),
    user-agent = getUserAgent(),
  };
  __request.headers.content-type = `multipart/form-data; boundary=${boundary}`;
  var form = {
    OSSAccessKeyId = request.header.accessKeyId,
    policy = request.header.policy,
    Signature = request.header.signature,
    key = request.header.key,
    success_action_status = request.header.successActionStatus,
    file = request.header.file,
    ...OSSUtil.toMeta(request.header.userMeta, 'x-oss-meta-'),
  };
  __request.body = FileForm.toFileForm(form, boundary);
} returns {
  var respMap : object = null;
  var bodyStr = Util.readAsString(__response.body);
  if (Util.is4xx(__response.statusCode) || Util.is5xx(__response.statusCode)) {
    respMap = OSSUtil.getErrMessage(bodyStr);
    throw {
      code = respMap.Code,
      message = respMap.Message,
      data = {
        httpCode = __response.statusCode,
        requestId = respMap.RequestId,
        hostId = respMap.HostId,
      }
    };
  }

  respMap = XML.parseXml(bodyStr, PostObjectResponse);
  return {
    ...respMap,
  };
} runtime {
  timeouted = 'retry',
  readTimeout = Util.defaultNumber(runtime.readTimeout, @readTimeout),
  connectTimeout = Util.defaultNumber(runtime.connectTimeout, @connectTimeout),
  httpProxy = Util.defaultString(runtime.httpProxy, @httpProxy),
  httpsProxy = Util.defaultString(runtime.httpsProxy, @httpsProxy),
  noProxy = Util.defaultString(runtime.noProxy, @noProxy),
  maxIdleConns = Util.defaultNumber(runtime.maxIdleConns, @maxIdleConns),
  retry = {
    retryable = runtime.autoretry,
    maxAttempts = Util.defaultNumber(runtime.maxAttempts, 3)
  },
  backoff = {
    policy = Util.defaultString(runtime.backoffPolicy, 'no'),
    period = Util.defaultNumber(runtime.backoffPeriod, 1)
  },
  ignoreSSL = runtime.ignoreSSL
}